From 5b3b8adbcf3e45516ade76f05f641c5681fdcda1 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Thu, 16 Dec 2021 16:49:22 +0000 Subject: [PATCH 1/2] Add feature checking support to go-criu This adds the feature checking interface with the same semantics as the feature checking through libcriu. Signed-off-by: Adrian Reber --- Makefile | 5 ++++ features.go | 45 ++++++++++++++++++++++++++++++++++ main.go | 14 +++++++---- test/main.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 features.go diff --git a/Makefile b/Makefile index 558e61453..0e04c8b7f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,11 @@ SHELL = /bin/bash GO ?= go CC ?= gcc COVERAGE_PATH ?= $(shell pwd)/.coverage +CRIU_FEATURE_MEM_TRACK = $(shell if criu check --feature mem_dirty_track > /dev/null; then echo 1; else echo 0; fi) +CRIU_FEATURE_LAZY_PAGES = $(shell if criu check --feature uffd-noncoop > /dev/null; then echo 1; else echo 0; fi) +CRIU_FEATURE_PIDFD_STORE = $(shell if criu check --feature pidfd_store > /dev/null; then echo 1; else echo 0; fi) + +export CRIU_FEATURE_MEM_TRACK CRIU_FEATURE_LAZY_PAGES CRIU_FEATURE_PIDFD_STORE all: build test phaul-test diff --git a/features.go b/features.go new file mode 100644 index 000000000..c7127f951 --- /dev/null +++ b/features.go @@ -0,0 +1,45 @@ +package criu + +import ( + "fmt" + + "github.com/checkpoint-restore/go-criu/v5/rpc" +) + +// Feature checking in go-criu is based on the libcriu feature checking function. + +// Feature checking allows the user to check if CRIU supports +// certain features. There are CRIU features which do not depend +// on the version of CRIU but on kernel features or architecture. +// +// One example is memory tracking. Memory tracking can be disabled +// in the kernel or there are architectures which do not support +// it (aarch64 for example). By using the feature check a libcriu +// user can easily query CRIU if a certain feature is available. +// +// The features which should be checked can be marked in the +// structure 'struct criu_feature_check'. Each structure member +// that is set to true will result in CRIU checking for the +// availability of that feature in the current combination of +// CRIU/kernel/architecture. +// +// Available features will be set to true when the function +// returns successfully. Missing features will be set to false. + +func (c *Criu) FeatureCheck(features *rpc.CriuFeatures) (*rpc.CriuFeatures, error) { + resp, err := c.doSwrkWithResp( + rpc.CriuReqType_FEATURE_CHECK, + nil, + nil, + features, + ) + if err != nil { + return nil, err + } + + if resp.GetType() != rpc.CriuReqType_FEATURE_CHECK { + return nil, fmt.Errorf("Unexpected CRIU RPC response") + } + + return features, nil +} diff --git a/main.go b/main.go index 78811c309..88b1b2458 100644 --- a/main.go +++ b/main.go @@ -87,19 +87,19 @@ func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) { } func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error { - resp, err := c.doSwrkWithResp(reqType, opts, nfy) + resp, err := c.doSwrkWithResp(reqType, opts, nfy, nil) if err != nil { return err } respType := resp.GetType() if respType != reqType { - return errors.New("unexpected responce") + return errors.New("unexpected CRIU RPC response") } return nil } -func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) { +func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (*rpc.CriuResp, error) { var resp *rpc.CriuResp req := rpc.CriuReq{ @@ -111,6 +111,10 @@ func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy N opts.NotifyScripts = proto.Bool(true) } + if features != nil { + req.Features = features + } + if c.swrkCmd == nil { err := c.Prepare() if err != nil { @@ -209,7 +213,7 @@ func (c *Criu) StartPageServer(opts *rpc.CriuOpts) error { // StartPageServerChld starts the page server and returns PID and port func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) { - resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil) + resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil, nil) if err != nil { return 0, 0, err } @@ -220,7 +224,7 @@ func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) { // GetCriuVersion executes the VERSION RPC call and returns the version // as an integer. Major * 10000 + Minor * 100 + SubLevel func (c *Criu) GetCriuVersion() (int, error) { - resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil) + resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil, nil) if err != nil { return 0, err } diff --git a/test/main.go b/test/main.go index 6ef8901b8..a985ecb49 100644 --- a/test/main.go +++ b/test/main.go @@ -58,6 +58,69 @@ func doDump(c *criu.Criu, pidS string, imgDir string, pre bool, prevImg string) return nil } +func featureCheck(c *criu.Criu) error { + features := &rpc.CriuFeatures{} + featuresToCompare := &rpc.CriuFeatures{} + env := os.Getenv("CRIU_FEATURE_MEM_TRACK") + if env != "" { + val, err := strconv.Atoi(env) + if err != nil { + return err + } + features.MemTrack = proto.Bool(val != 0) + featuresToCompare.MemTrack = proto.Bool(val != 0) + } + env = os.Getenv("CRIU_FEATURE_LAZY_PAGES") + if env != "" { + val, err := strconv.Atoi(env) + if err != nil { + return err + } + features.LazyPages = proto.Bool(val != 0) + featuresToCompare.LazyPages = proto.Bool(val != 0) + } + env = os.Getenv("CRIU_FEATURE_PIDFD_STORE") + if env != "" { + val, err := strconv.Atoi(env) + if err != nil { + return err + } + features.PidfdStore = proto.Bool(val != 0) + featuresToCompare.PidfdStore = proto.Bool(val != 0) + } + + features, err := c.FeatureCheck(features) + if err != nil { + return err + } + + if *features.MemTrack != *featuresToCompare.MemTrack { + return fmt.Errorf( + "Unexpected MemTrack FeatureCheck result %v:%v", + *features.MemTrack, + *featuresToCompare.MemTrack, + ) + } + + if *features.LazyPages != *featuresToCompare.LazyPages { + return fmt.Errorf( + "Unexpected LazyPages FeatureCheck result %v:%v", + *features.LazyPages, + *featuresToCompare.LazyPages, + ) + } + + if *features.PidfdStore != *featuresToCompare.PidfdStore { + return fmt.Errorf( + "Unexpected PidfdStore FeatureCheck result %v:%v", + *features.PidfdStore, + *featuresToCompare.PidfdStore, + ) + } + + return nil +} + // Usage: test $act $pid $images_dir func main() { c := criu.MakeCriu() @@ -76,6 +139,11 @@ func main() { if !result { log.Fatalln("CRIU version to old") } + + if err = featureCheck(c); err != nil { + log.Fatalln(err) + } + act := os.Args[1] switch act { case "dump": From 200ac0cb2bc849dc534153e0842828ff6a784238 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Fri, 17 Dec 2021 10:00:20 +0000 Subject: [PATCH 2/2] Fix coverage processing Signed-off-by: Adrian Reber --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0e04c8b7f..67c43a05b 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,8 @@ coverage: $(COVERAGE_BINARIES) $(TEST_PAYLOAD) test/phaul/phaul.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE $$PID; \ pkill -9 piggie; \ } + echo "mode: set" > .coverage/coverage.out && cat .coverage/coverprofile* | \ + grep -v mode: | sort -r | awk '{if($$1 != last) {print $$0;last=$$1}}' >> .coverage/coverage.out clean: @rm -f $(TEST_BINARIES) $(COVERAGE_BINARIES) codecov @@ -100,6 +102,6 @@ vendor: codecov: curl -Os https://uploader.codecov.io/latest/linux/codecov chmod +x codecov - ./codecov -f '.coverage/*' + ./codecov -f '.coverage/coverage.out' .PHONY: build test phaul-test test-bin clean lint vendor coverage codecov