Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature checking support to go-criu #60

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -70,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
Expand All @@ -95,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
45 changes: 45 additions & 0 deletions features.go
Original file line number Diff line number Diff line change
@@ -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
}
14 changes: 9 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down
68 changes: 68 additions & 0 deletions test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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":
Expand Down